package com.example.yupao_project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.yupao_project.component.ErrorCode;
import com.example.yupao_project.component.HandlingPrivacy;
import com.example.yupao_project.component.PasswordUtil;
import com.example.yupao_project.component.SessionUtil;
import com.example.yupao_project.entity.User;
import com.example.yupao_project.entity.param.UserInfoVo;
import com.example.yupao_project.exception.BusinessException;
import com.example.yupao_project.mapper.UserMapper;
import com.example.yupao_project.service.UserService;
import com.example.yupao_project.utils.AlgorithmUtils;
import com.example.yupao_project.utils.AppVar;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.math3.util.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.example.yupao_project.component.HandlingPrivacy.handlingPrivacy;

/**
 * @author 杰
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2024-04-27 19:57:37
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private UserMapper userMapper;

    @Autowired
    private PasswordUtil passwordUtil;

    @Resource
    private SessionUtil sessionUtil;

    /**
     * 注册功能
     *
     * @param userInfoVo 用户注册信息
     * @return ResultUtils
     */
    @Override
    public String register(UserInfoVo userInfoVo) {
        //1.校验数据
        //判断数据是否为空
        if (!StringUtils.hasLength(userInfoVo.getUsername())) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        if (userInfoVo.getUsername().length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户名过短");
        }
        if (!StringUtils.hasLength(userInfoVo.getUserAccount())) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "账号为空");
        }
        if (userInfoVo.getUserAccount().length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号小于4位");
        }
        if (!StringUtils.hasLength(userInfoVo.getUserPassword())) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "密码为空");
        }
        if (userInfoVo.getUserPassword().length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码小于8位");
        }
        if (!StringUtils.hasLength(userInfoVo.getConfirmPassword())) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "确认密码为空");
        }
        if (!userInfoVo.getUserPassword().equals(userInfoVo.getConfirmPassword()))
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次密码输入不正确");
        //判断数据是否含有特殊字符
        String regex = "^[a-zA-Z0-9_]*$";//字母、数字和下划线组成
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(userInfoVo.getUserAccount());
        //含有特殊字符
        if (!matcher.matches()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号中含有特殊字符");
        }

        //此userAccount是否被注册
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userInfoVo.getUserAccount());
        User eqUser = userMapper.selectOne(queryWrapper);
        if (eqUser != null && eqUser.getId() > 0) {
            //已经存在userAccount
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "此账号已存在");
        }
        //2.加密数据（MD5 + 盐值）,得到盐值+加密后的数据
        //调用加密数据
        String encryptData = passwordUtil.encrypt(userInfoVo.getUserPassword());
        //3.存入数据库
        User user = new User();
        user.setUsername(userInfoVo.getUsername());
        user.setUserAccount(userInfoVo.getUserAccount());
        //将加密后的最终密码和盐值存入数据库
        user.setUserPassword(encryptData);
        userMapper.insert(user);
        //4.返回成功
        return userInfoVo.getUserAccount();
    }

    /**
     * 登录功能
     *
     * @param userAccount  账号
     * @param userPassword 密码
     * @return ResultUtils
     */
    @Override
    public String login(String userAccount, String userPassword, HttpSession session) {
        //1.校验数据
        if (!StringUtils.hasLength(userAccount)) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "账号为空");
        }
        if (!StringUtils.hasLength(userPassword)) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "密码为空");
        }
        //2.判断账号密码是否正确
        User eqUser = passwordUtil.decrypt(userAccount, userPassword);
        if (eqUser == null) throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号或密码错误");
        handlingPrivacy(eqUser);
        //存入session
        session.setAttribute(AppVar.SESSION_KEY_USERINFO, eqUser);
        //返回账号
        return userAccount;
    }

    /**
     * 通过标签搜索用户
     *
     * @param tagList 标签
     * @return ResultUtils
     */
    @Override
    public List<User> searchUserByTags(List<String> tagList) {
        if (tagList.isEmpty())
            throw new BusinessException(ErrorCode.NULL_ERROR, "标签为空");
        //通过数据库查询
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        for (String tag : tagList) {
            queryWrapper = queryWrapper.like("tags", tag);
        }
        List<User> usersList = userMapper.selectList(queryWrapper);
        for (User user : usersList)
            handlingPrivacy(user);
        return usersList;
    }

    /**
     * 更新用户信息
     *
     * @param user 信息
     * @return ResultUtils
     */
    @Override
    public boolean updateUserInfo(User user, HttpServletRequest request) {
        if (user == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "用户为空");
        }
        if (userMapper.updateById(user) == 0)
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询失败");
        //更新session
        updateSession(user, request);
        return true;
    }

    /**
     * 用户更新信息之后更新session
     *
     * @param user    用户信息
     * @param request request
     */
    @Override
    public void updateSession(User user, HttpServletRequest request) {
        User loginUser = userMapper.selectById(user.getId());
        HttpSession session = request.getSession();
        session.setAttribute(AppVar.SESSION_KEY_USERINFO, loginUser);
    }

    /**
     * 根据标签自动匹配伙伴
     *
     * @param num     人物个数
     * @param request 登录用户
     * @return List<User>
     */
    @Override
    public List<User> matchUsers(long num, HttpServletRequest request) {
        //校验参数
        if (num <= 0 || num > 20) throw new BusinessException(ErrorCode.PARAMS_ERROR);
        User loginUser = (User) sessionUtil.getSession(request);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "tags");
        queryWrapper.isNotNull("tags");
        //获取用户标签
        List<User> userList = this.list(queryWrapper);
        String tags = loginUser.getTags();
        Gson gson = new Gson();
        List<String> tagList = gson.fromJson(tags, new TypeToken<List<String>>() {
        }.getType());
        // 用户列表的下标 => 相似度
        List<Pair<User, Long>> list = new ArrayList<>();
        // 依次计算所有用户和当前用户的相似度
        for (int i = 0; i < userList.size(); i++) {
            User user = userList.get(i);
            String userTags = user.getTags();
            // 无标签或者为当前用户自己
            if (!StringUtils.hasLength(userTags) || user.getId() == loginUser.getId()) {
                continue;
            }
            List<String> userTagList = gson.fromJson(userTags, new TypeToken<List<String>>() {
            }.getType());
            // 计算分数
            long distance = AlgorithmUtils.minDistance(tagList, userTagList);
            list.add(new Pair<>(user, distance));
        }
        // 按编辑距离由小到大排序
        List<Pair<User, Long>> topUserPairList = list.stream()
                .sorted((a, b) -> (int) (a.getValue() - b.getValue()))
                .limit(num)
                .toList();
        // 原本顺序的 userId 列表
        List<Long> userIdList = topUserPairList.stream().map(pair -> pair.getKey().getId()).collect(Collectors.toList());
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.in("id", userIdList);
        // 1, 3, 2
        // User1、User2、User3
        // 1 => User1, 2 => User2, 3 => User3
        Map<Long, List<User>> userIdUserListMap = this.list(userQueryWrapper)
                .stream()
                .map(HandlingPrivacy::handlingPrivacy)
                .collect(Collectors.groupingBy(User::getId));
        List<User> finalUserList = new ArrayList<>();
        for (Long userId : userIdList) {
            finalUserList.add(userIdUserListMap.get(userId).get(0));
        }
        return finalUserList;
    }


}




